package com.mulanweb.tools;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.dialect.SqlServerDialect;
import com.jfinal.plugin.activerecord.generator.ColumnMeta;
import com.jfinal.plugin.activerecord.generator.MetaBuilder;
import com.jfinal.plugin.activerecord.generator.TableMeta;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by hcy on 2016/4/11.
 */
public class SqlServerMetaBuilder extends MetaBuilder {
    public SqlServerMetaBuilder(DataSource dataSource) {
        super(dataSource);
        super.setDialect(new SqlServerDialect());
    }

    @Override
    public List<TableMeta> build() {
        System.out.println("Build TableMeta ...");
        try {
            conn = dataSource.getConnection();
            dbMeta = conn.getMetaData();

            List<TableMeta> ret = new ArrayList<TableMeta>();
            buildTableNames(ret);
            for (TableMeta tableMeta : ret) {
                System.out.println(tableMeta.modelName);
                buildPrimaryKey(tableMeta);
                buildColumnMetas(tableMeta);
            }
            return ret;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            if (conn != null)
                try {
                    conn.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
        }
    }

    @Override
    protected void buildPrimaryKey(TableMeta tableMeta) throws SQLException {
        ResultSet rs = dbMeta.getPrimaryKeys(conn.getCatalog(), null, tableMeta.name.replace("[", "").replace("]", ""));

        String primaryKey = "";
        int index = 0;
        while (rs.next()) {
            if (index++ > 0)
                primaryKey += ",";
            primaryKey =primaryKey.concat(rs.getString("COLUMN_NAME"));
        }
        tableMeta.primaryKey = primaryKey;
        rs.close();
    }

    @Override
    protected void buildTableNames(List<TableMeta> ret) throws SQLException {
        ResultSet rs = getTablesResultSet();
        while (rs.next()) {
            String tableName = rs.getString("TABLE_NAME");

            if (excludedTables.contains(tableName)) {
                System.out.println("Skip table :" + tableName);
                continue;
            }
            if (isSkipTable(tableName)) {
                System.out.println("Skip table :" + tableName);
                continue;
            }

            TableMeta tableMeta = new TableMeta();
            tableMeta.name = '[' + tableName + ']';
            tableMeta.remarks = rs.getString("REMARKS");

            tableMeta.modelName = buildModelName(tableName);
            tableMeta.baseModelName = buildBaseModelName(tableMeta.modelName);
            ret.add(tableMeta);
        }
        rs.close();
    }

    @Override
    protected ResultSet getTablesResultSet() throws SQLException {
        return dbMeta.getTables(conn.getCatalog(), null, null, new String[]{"TABLE"});
    }

    @Override
    protected String buildBaseModelName(String modelName) {
        return modelName.replaceFirst("M", "Base");
    }


    @Override
    protected String buildModelName(String tableName) {
        return "M" + tableName;
    }

    @Override
    protected boolean isSkipTable(String tableName) {
        return tableName.charAt(0) > 'Z';
    }

    @Override
    protected String buildAttrName(String colName) {
        return StrKit.firstCharToLowerCase(colName);
    }

    @Override
    protected void buildColumnMetas(TableMeta tableMeta) throws SQLException {
        String sql = dialect.forTableBuilderDoBuild(tableMeta.name);
        Statement stm = conn.createStatement();
        ResultSet rs = stm.executeQuery(sql);
        ResultSetMetaData rsmd = rs.getMetaData();

        for (int i = 1; i <= rsmd.getColumnCount(); i++) {
            ColumnMeta cm = new ColumnMeta();
            cm.name = rsmd.getColumnName(i);

            String colClassName = rsmd.getColumnClassName(i);
            String typeStr = typeMapping.getType(colClassName);
            if (typeStr != null) {
                if (typeStr.startsWith("java.lang.")) {
                    typeStr = typeStr.replace("java.lang.", "");
                }
                cm.javaType = typeStr;
            } else {
                int type = rsmd.getColumnType(i);
                if (type == Types.BINARY || type == Types.VARBINARY || type == Types.BLOB) {
                    cm.javaType = "byte[]";
                } else if (type == Types.CLOB || type == Types.NCLOB) {
                    cm.javaType = "String";
                } else {
                    cm.javaType = "String";
                }
            }

            // 构造字段对应的属性名 attrName
            cm.attrName = buildAttrName(cm.name);

            tableMeta.columnMetas.add(cm);
        }

        rs.close();
        stm.close();
    }
}
